Skip to content

SK-3253:Add gated retry on 401 status code for flowvault SDK - #454

Merged
yaswanth-pula-skyflow merged 8 commits into
mainfrom
flowvault-release/26.10.28
Oct 29, 2026
Merged

yaswanth-pula-skyflow merged 8 commits into
mainfrom
flowvault-release/26.10.28

Conversation

@yaswanth-pula-skyflow

Copy link
Copy Markdown
Collaborator

SK-3253: Retry once on 401 when the bearer token expired mid-call

Ticket: SK-3253 (customer case CUST-4591)

Problem

Every vault method checks the bearer token once, at its start, with now > exp. The token is then used for every HTTP request that method sends. If it expires while a request is in flight, or between the check and a later request of the same method, the gateway answers 401 and the SDK returns that as the result. Nothing regenerates the token until the next method call.

In flowvault a bulk method splits records into batches and sends each batch as its own request under that one check. A customer's bulk tokenize of 2,000 records started a few seconds before expiry, passed the check, and lost every batch after exp as per-record httpCode=401 errors.

Fix

When a request fails with 401 and the SDK can see from its own copy of the token that the token is at or past expiry, the SDK generates a new token once and resends that request once.

  • Trigger is 401 only. Any other status is returned as today.
  • Only for credentials the SDK can mint from: service-account file, credentials string, environment credentials. A static token (setToken) or an API key returns the 401 unchanged.
  • Only when the sent token's exp is within 60 seconds of now. A 401 on a token with more life than that is not expiry and is returned unchanged, with no token generated.
  • One regeneration and one resend per request. The response to the resend is returned whatever it is.
  • Single-flight. Regeneration is serialised with the existing token check. A request that finds the cache already holds a different token reuses it, so concurrent 401s on one token cost one generation.
  • If generation fails, or returns the token that was just rejected, the original 401 is returned.

Later requests in the same method read the refreshed token from the cache, so a bulk call that crosses expiry now completes in full. No new configuration. The start-of-method check is unchanged.

Changes

common

  • BaseVaultClient: the auth interceptor used by every OkHttp client now handles the 401 branch. New refreshBearerTokenAfterUnauthorized implements the rules above, synchronized with setBearerToken. Token reads go through a synchronized getToken() so a token refreshed on one thread is seen by the others.
  • Token.isExpiringWithin(token, windowSeconds): public, additive. isExpired is unchanged.
  • New InfoLogs / WarningLogs entries for the refresh path. No new logging on the happy path.

flowvault

  • VaultClient: uses the shared auth interceptor from common. The transport retry interceptor stays outside it, so configured 408/429/5xx retries and the call timeout still bound the whole exchange.

skyvault

  • VaultClient: token supplier switched to getToken(). Vault and detect calls get the retry through the shared interceptor.
  • Connections are intentionally unchanged. A connection 401 can come from the proxied third party, and a resend there is not guaranteed to be side-effect free.

Not covered, by design

setToken tokens, API keys, any 401 on a token that is not near expiry, a connection call that straddles expiry. All behave exactly as today.

Tests

  • common: BaseVaultClientTests (interceptor branches, gate, single-flight, same-token-back, failure), TokenTests (isExpiringWithin boundaries, malformed and missing exp).
  • flowvault: AuthInterceptorTests (retry ordering, resend once, static token and API key untouched).
  • All three module suites pass. flowvault japicmp against the baseline passes; the only public API change is the new Token.isExpiringWithin.

@github-actions

Copy link
Copy Markdown

✅ Gitleaks Findings: No secrets detected. Safe to proceed!

@github-actions

Copy link
Copy Markdown

Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging.

@codecov

codecov Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.29%. Comparing base (e210d03) to head (eb41b64).

Additional details and impacted files
@@             Coverage Diff              @@
##               main     #454      +/-   ##
============================================
+ Coverage     91.00%   91.29%   +0.29%     
- Complexity        0      571     +571     
============================================
  Files           174      174              
  Lines          7350     7401      +51     
  Branches       1013     1023      +10     
============================================
+ Hits           6689     6757      +68     
+ Misses          437      422      -15     
+ Partials        224      222       -2     
Flag Coverage Δ
common 90.82% <100.00%> (+1.36%) ⬆️
flowvault 87.92% <100.00%> (-0.02%) ⬇️
skyvault 94.98% <100.00%> (+0.13%) ⬆️
unittests-flowvault 90.42% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Module: common 90.82% <100.00%> (+1.36%) ⬆️
Module: skyvault 94.98% <100.00%> (+0.13%) ⬆️
Module: flowvault 87.92% <100.00%> (-0.02%) ⬇️
Service Account 87.76% <100.00%> (+0.39%) ⬆️
Vault Data 90.81% <ø> (ø)
Vault Tokens 99.03% <ø> (ø)
Vault Connection 100.00% <ø> (ø)
Vault Controller 82.75% <ø> (ø)
Detect 100.00% <ø> (ø)
Audit 100.00% <ø> (ø)
BIN Lookup 100.00% <ø> (ø)
Config 96.26% <ø> (ø)
Utils 90.53% <ø> (+0.12%) ⬆️
Errors 100.00% <ø> (ø)
Enums 100.00% <ø> (ø)
Logs 100.00% <100.00%> (+4.39%) ⬆️
Files with missing lines Coverage Δ
...mon/src/main/java/com/skyflow/BaseVaultClient.java 92.39% <100.00%> (+5.85%) ⬆️
...ommon/src/main/java/com/skyflow/logs/InfoLogs.java 100.00% <100.00%> (ø)
...on/src/main/java/com/skyflow/logs/WarningLogs.java 100.00% <100.00%> (+100.00%) ⬆️
...in/java/com/skyflow/serviceaccount/util/Token.java 96.96% <100.00%> (+1.13%) ⬆️
...owvault/src/main/java/com/skyflow/VaultClient.java 97.26% <100.00%> (-0.15%) ⬇️
...kyvault/src/main/java/com/skyflow/VaultClient.java 97.80% <100.00%> (+0.19%) ⬆️

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e210d03...eb41b64. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@yaswanth-pula-skyflow
yaswanth-pula-skyflow merged commit 3c8d25a into main Oct 29, 2026
32 checks passed
skyflow-himanshupal pushed a commit that referenced this pull request Nov 10, 2026
* SK-3253:Add gated retry on 401 status code for both skyvault & flowvault SDKs.

* SK-3253:Fix failed token regeneration when concurent 401 failures.

* SK-3253:Update unit tests to cover both skyvault & flowvault.

* SK-3252:Update null check.

* [AUTOMATED] Private Release 1.2.0-dev-23391b03

* SK-3253:Update warning log & test.

* [AUTOMATED] Private Release 1.2.0-dev-20ef0615

---------

Co-authored-by: yaswanth-pula-skyflow <yaswanth-pula-skyflow@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants